package com.gwd.task.services.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import com.gwd.task.entity.ProductionEventsEntity;
import com.gwd.task.exception.DataException;
import com.gwd.task.model.*;
import com.gwd.task.repository.ProductionEventsRepository;
import com.gwd.task.services.*;
import com.gwd.task.untils.ListPredicate;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * @author zhiyongming
 * @date 2020/12/2 18:04
 */
@Service
public class ProductionEventsServerImpl implements ProductionEventsServer {

    @Resource
    private UserServer userServer;
    @Resource
    private ProjectServer projectServer;
    @Resource
    private ProjectModuleServer projectModuleServer;
    @Resource
    private ProductionEventsRepository eventsRepository;
    @Resource
    private AttachmentServer attachmentServer;
    @Resource
    private ProjectNumServer projectNumServer;
    @Resource
    private EventsProcessServer eventsProcessServer;
    @Resource
    private CodeSubmitRecordServer codeSubmitRecordServer;

    //事件状态
    private final static Integer PE_STATE_UN_FINISH = 0; //未解决
    private final static Integer PE_STATE_FINISH = 1; //已解决
    private final static Integer PE_STATE_CLOSE = 2;  //关闭
    //开发状态
    private final static Integer DEV_STATE_DISPATCH = 1;  //分配完成
    private final static Integer DEV_STATE_SUBMIT = 2;  //提交完成
    private final static Integer DEV_STATE_TEST = 3;  //测试中
    private final static Integer DEV_STATE_FINISH = 4;  //完成
    private final static Integer DEV_STATE_CLOSE = 5;  //关闭

    @Override
    public PageUtils findByPage(ProductionEventsDTO dto, PageUtils pageUtils) {
        Page<ProductionEventsEntity> page
                = eventsRepository.findAll((Specification<ProductionEventsEntity>)
            (root, query, cb) ->
                ListPredicate.of(root, query, cb)
                    .equal("group", dto.getGroup())
                    .equal("projectId", dto.getProjectId())
                    .equal("lv2ModuleId", dto.getLv2ModuleId())
                    .equal("respPerson", dto.getRespPerson())
                    .equal("devPerson", dto.getDevPerson())
                    .equal("testPerson", dto.getTestPerson())
                    .equal("peStatus", dto.getPeStatus())
                    .equal("devStatus", dto.getDevStatus())
                    .ge("record", dto.getRecordBegin())
                    .gt("record", dto.getRecordEnd())
                    .finish()
                    .getRestriction(),
                pageUtils.convert("peId", "desc"));

        List<ProductionEventsDTO> list = page.get().map(ProductionEventsDTO::new).collect(Collectors.toList());

        //匹配项目名称
        List<ProjectDTO> projectDTOList = projectServer.findAll();
        list.forEach(event -> projectDTOList.forEach(project -> {
            if (event.getProjectId().equals(project.getProjectId())) {
                event.setProjectName(project.getProjectName());
            }
        }));

        //匹配模块名称
        List<ProjectModuleDTO> projectModuleDTOS = projectModuleServer.findAll();
        list.forEach(event -> projectModuleDTOS.forEach(module -> {
            if (event.getLv1ModuleId().equals(module.getModuleId())) {
                event.setLv1ModuleName(module.getModuleName());
            }
            if (event.getLv2ModuleId().equals(module.getModuleId())) {
                event.setLv2ModuleName(module.getModuleName());
            }
        }));

        //匹配用户名称
        List<UserDTO> userDTOList = userServer.findAll();
        list.forEach(event -> userDTOList.forEach(user -> {
            if (event.getDevPerson().equals(user.getUserId())) {
                event.setDevPersonName(user.getUserName());
            }
            if (event.getTestPerson().equals(user.getUserId())) {
                event.setTestPersonName(user.getUserName());
            }
            if (event.getRespPerson().equals(user.getUserId())) {
                event.setRespPersonName(user.getUserName());
            }
        }));

        //匹配附件
        List<AttachmentDTO> attachList = attachmentServer.findByCodeList(list.stream().
                map(ProductionEventsDTO::getPeCode).collect(Collectors.toList()));
        list.forEach(event -> attachList.forEach(att -> {
            if (att.getCode().equals(event.getPeCode())) {
                event.addAttachment(att);
            }
        }));

        //匹配操作日志
        List<EventsProcessDTO> processes =
                eventsProcessServer.findByEventIdList(list.stream().map(ProductionEventsDTO::getPeId).collect(Collectors.toList()));
        list.forEach(event -> processes.forEach(p -> {
            if (event.getPeId().equals(p.getEventId())) {
                event.addProcess(p);
            }
        }));

        pageUtils.convert(page).setContent(list);
        return pageUtils;
    }

    @Override
    public void save(ProductionEventsDTO dto, Long id) {
        ProductionEventsEntity save;
        if (dto.getPeId()!=null) {
            Optional<ProductionEventsEntity> entity = eventsRepository.findById(dto.getPeId());
            if (!entity.isPresent()) {
                throw new DataException("PeId:" + dto.getPeId() + " 对应的数据不存在!");
            }
            save = entity.get();
        } else {
            save = new ProductionEventsEntity();
            save.setPeStatus(0);
            save.setDevStatus(0);
            save.setRecord(DatePattern.NORM_DATETIME_MINUTE_FORMAT.format(new Date()));
            save.setPeCode(projectNumServer.getEvent(dto.getProjectId()));
        }
        BeanUtil.copyProperties(dto, save, CopyOptions.create().setIgnoreNullValue(true).setIgnoreError(true));
        save.setLv1ModuleId(dto.getModuleId()[0]);
        save.setLv2ModuleId(dto.getModuleId()[1]);

        ProductionEventsEntity entity = eventsRepository.save(save);

        // 把临时的编号绑定上
        attachmentServer.bindCode(dto.getAttachments(), entity.getPeCode());

        //新增操作日志
        if (dto.getPeId()==null) {
            eventsProcessServer.save(EventsProcessDTO.CREATE(id, entity.getPeId()));
        }
    }

    @Override
    public HSSFWorkbook export(ProductionEventsDTO dto) {
        PageUtils pageUtils = new PageUtils();
        pageUtils.setPageNum(1);
        pageUtils.setPageSize(100000000);
        List<?> content = findByPage(dto, pageUtils).getContent();
        if (content.isEmpty()) {
            return null;
        }
        List<ProductionEventsDTO> list = (List<ProductionEventsDTO>) content;
        HSSFWorkbook workbook = new HSSFWorkbook();
        HSSFCellStyle cellStyle = workbook.createCellStyle();
        cellStyle.setFillForegroundColor(IndexedColors.LIGHT_CORNFLOWER_BLUE.index);
        cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        cellStyle.setAlignment(HorizontalAlignment.CENTER_SELECTION);

        HSSFCellStyle leftCellStyle = workbook.createCellStyle();
        leftCellStyle.setAlignment(HorizontalAlignment.LEFT);
        leftCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);

        HSSFCellStyle centerCellStyle = workbook.createCellStyle();
        centerCellStyle.setAlignment(HorizontalAlignment.CENTER_SELECTION);
        centerCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);

        HSSFSheet sheet = workbook.createSheet();
        HSSFRow row = sheet.createRow(0);


        HSSFCell hssfCell0 = row.createCell(0);
        HSSFCell hssfCell1 = row.createCell(1);
        HSSFCell hssfCell2 = row.createCell(2);
        HSSFCell hssfCell3 = row.createCell(3);
        HSSFCell hssfCell4 = row.createCell(4);
        HSSFCell hssfCell5 = row.createCell(5);
        HSSFCell hssfCell6 = row.createCell(6);
        HSSFCell hssfCell7 = row.createCell(7);
        HSSFCell hssfCell8 = row.createCell(8);
        HSSFCell hssfCell9 = row.createCell(9);
        HSSFCell hssfCell10 = row.createCell(10);
        HSSFCell hssfCell11 = row.createCell(11);

        hssfCell0.setCellValue("生产状态");
        hssfCell0.setCellValue("开发状态");
        hssfCell1.setCellValue("编号");
        hssfCell3.setCellValue("发现时间");
        hssfCell4.setCellValue("项目");
        hssfCell5.setCellValue("模块");
        hssfCell6.setCellValue("子模块");
        hssfCell7.setCellValue("开发负责人");
        hssfCell8.setCellValue("测试负责人");
        hssfCell9.setCellValue("预计修复时间");
        hssfCell10.setCellValue("预计上线时间");
        hssfCell11.setCellValue("问题描述");

        hssfCell0.setCellStyle(cellStyle);
        hssfCell1.setCellStyle(cellStyle);
        hssfCell2.setCellStyle(cellStyle);
        hssfCell3.setCellStyle(cellStyle);
        hssfCell4.setCellStyle(cellStyle);
        hssfCell5.setCellStyle(cellStyle);
        hssfCell6.setCellStyle(cellStyle);
        hssfCell7.setCellStyle(cellStyle);
        hssfCell8.setCellStyle(cellStyle);
        hssfCell9.setCellStyle(cellStyle);
        hssfCell10.setCellStyle(cellStyle);
        hssfCell11.setCellStyle(cellStyle);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        for (int i=0; i<list.size(); i++) {
            HSSFRow rowI = sheet.createRow(i+1);
            rowI.createCell(0).setCellValue(list.get(i).getPeStatusName());
            rowI.createCell(1).setCellValue(list.get(i).getDevStatusName());
            rowI.createCell(2).setCellValue(list.get(i).getPeCode());
            rowI.createCell(3).setCellValue(simpleDateFormat.format(list.get(i).getRecord()));
            rowI.createCell(4).setCellValue(list.get(i).getProjectName());
            rowI.createCell(5).setCellValue(list.get(i).getLv1ModuleName());
            rowI.createCell(6).setCellValue(list.get(i).getLv2ModuleName());
            rowI.createCell(7).setCellValue(list.get(i).getDevPersonName());
            rowI.createCell(8).setCellValue(list.get(i).getTestPersonName());
            rowI.createCell(9).setCellValue(simpleDateFormat.format(list.get(i).getPreRepair()!=null?list.get(i).getPreRepair():""));
            rowI.createCell(10).setCellValue(simpleDateFormat.format(list.get(i).getPreOnline()!=null?list.get(i).getPreOnline():""));
            rowI.createCell(11).setCellValue(list.get(i).getDescribe());
        }


        sheet.setColumnWidth(0, (int)35.7*80);
        sheet.setColumnWidth(1, (int)35.7*100);
        sheet.setColumnWidth(3, (int)35.7*200);
        sheet.setColumnWidth(4, (int)35.7*100);
        sheet.setColumnWidth(5, (int)35.7*100);
        sheet.setColumnWidth(6, (int)35.7*100);
        sheet.setColumnWidth(7, (int)35.7*100);
        sheet.setColumnWidth(8, (int)35.7*100);
        sheet.setColumnWidth(9, (int)35.7*100);
        sheet.setColumnWidth(10, (int)35.7*100);
        sheet.setColumnWidth(11, (int)35.7*100);
        workbook.setSheetName(0,"sheet1");

        FileOutputStream out;
        String fileName = UUID.randomUUID().toString().replace("-", "");
        try {
            out = new FileOutputStream("E:\\files\\" + fileName);
            workbook.write(out);
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return workbook;
    }

    @Override
    public void remove(Long id) {
        eventsRepository.deleteById(id);
    }

    @Override
    public ProductionEventsDTO findById(Long peId) {
        return null;
    }

    @Override
    public List<ProductionEventsDTO> findAllById(List<Long> ids) {
        return eventsRepository.findAllById(ids).stream().map(ProductionEventsDTO::new).collect(Collectors.toList());
    }

    @Override
    public List<ProductionEventsDTO> findByUserIdListAndUnClose(List<Long> ids) {
        return eventsRepository.findByDevPersonInAndPeStatus(ids, PE_STATE_UN_FINISH).stream()
                .map(ProductionEventsDTO::new).collect(Collectors.toList());
    }

    @Override
    public void start(Long peId, Long userId) {
        eventsRepository.findById(peId).ifPresent(e -> {
            e.setPeStatus(PE_STATE_UN_FINISH);
            e.setDevStatus(DEV_STATE_DISPATCH);

            eventsProcessServer.save(EventsProcessDTO.START(userId, peId));
        });
    }

    @Override
    public void restart(Long peId, Long userId) {
        eventsRepository.findById(peId).ifPresent(e -> {
            e.setPeStatus(PE_STATE_UN_FINISH);
            e.setDevStatus(DEV_STATE_DISPATCH);

            eventsProcessServer.save(EventsProcessDTO.RESTART(userId, peId));
        });
    }

    @Override
    public void submit(Long peId, Long userId, CodeSubmitRecordDTO csrDTO) {
        eventsRepository.findById(peId).ifPresent(e -> {
            e.setPeStatus(PE_STATE_UN_FINISH);
            e.setDevStatus(DEV_STATE_SUBMIT);

            eventsProcessServer.save(EventsProcessDTO.SUBMIT(userId, peId));

            //保存至提交记录中
            csrDTO.setCode(e.getPeCode());
            csrDTO.setSubmitUser(userId);
            csrDTO.setSubmitTime(DateTime.now().toStringDefaultTimeZone());
            csrDTO.setProjectId(e.getProjectId());
            csrDTO.setLv1ModuleId(e.getLv1ModuleId());
            csrDTO.setLv2ModuleId(e.getLv2ModuleId());
            csrDTO.setDescribe(e.getDescribe());
            csrDTO.setRelateId(peId);
            csrDTO.setTaskId(peId);
            csrDTO.setType(1); //生产

            codeSubmitRecordServer.save(csrDTO);
        });
    }

    @Override
    public void test(Long peId, Long userId) {
        eventsRepository.findById(peId).ifPresent(e -> {
            e.setPeStatus(PE_STATE_UN_FINISH);
            e.setDevStatus(DEV_STATE_TEST);

            eventsProcessServer.save(EventsProcessDTO.SUBMIT(userId, peId));
        });
    }

    @Override
    public void finish(Long peId, Long userId) {
        eventsRepository.findById(peId).ifPresent(e -> {
            e.setPeStatus(PE_STATE_FINISH);
            e.setDevStatus(DEV_STATE_FINISH);

            eventsProcessServer.save(EventsProcessDTO.SUBMIT(userId, peId));
        });
    }

    @Override
    public void close(Long peId, Long userId) {
        eventsRepository.findById(peId).ifPresent(e -> {
            e.setPeStatus(PE_STATE_CLOSE);
            e.setDevStatus(DEV_STATE_CLOSE);

            eventsProcessServer.save(EventsProcessDTO.CLOSE(userId, peId));
        });
    }

    @Override
    public void board(List<Long> ids) {
        eventsRepository.saveAll(eventsRepository.findAllById(ids).stream().peek(e -> e.setDevStatus(DEV_STATE_TEST)).collect(Collectors.toList()));
    }

    @Override
    public void changeDevPerson(Long peId, Long userId) {
        eventsRepository.findById(peId).ifPresent(e -> {
            e.setDevPerson(userId);
            eventsRepository.save(e);
        });
    }

    @Override
    public void changeTestPerson(Long peId, Long userId) {
        eventsRepository.findById(peId).ifPresent(e -> {
            e.setTestPerson(userId);
            eventsRepository.save(e);
        });
    }
}
